// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 
// Source File Name:   MessageFactory.java

package com.solab.iso8583;

import com.solab.iso8583.common.ByteUtil;
import com.solab.iso8583.parse.FieldParseInfo;
import java.text.ParseException;
import java.util.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

// Referenced classes of package com.solab.iso8583:
//			IsoMessage, IsoValue, TraceNumberGenerator, IsoType

public class MessageFactory
{

	protected static final Log log = LogFactory.getLog(MessageFactory.class);
	private Map typeTemplates;
	private Map parseMap;
	private Map parseOrder;
	private TraceNumberGenerator traceGen;
	private Map isoHeaders;
	private boolean setDate;
	private boolean useBinary;
	private int etx;

	public MessageFactory()
	{
		typeTemplates = new HashMap();
		parseMap = new HashMap();
		parseOrder = new HashMap();
		isoHeaders = new HashMap();
		etx = -1;
	}

	public void setUseBinaryMessages(boolean flag)
	{
		useBinary = flag;
	}

	public boolean getUseBinaryMessages()
	{
		return useBinary;
	}

	public void setEtx(int value)
	{
		etx = value;
	}

	public IsoMessage newMessage(int type)
	{
		Integer itype = new Integer(type);
		IsoMessage m = new IsoMessage((String)isoHeaders.get(itype));
		m.setType(type);
		m.setEtx(etx);
		m.setBinary(useBinary);
		IsoMessage templ = (IsoMessage)typeTemplates.get(itype);
		if (templ != null)
		{
			for (int i = 2; i < 128; i++)
				if (templ.hasField(i))
					m.setField(i, (IsoValue)templ.getField(i).clone());

		}
		if (traceGen != null)
			m.setValue(11, new Integer(traceGen.nextTrace()), IsoType.NUMERIC, 6);
		if (setDate)
			m.setValue(7, new Date(), IsoType.DATE10, 10);
		return m;
	}

	public IsoMessage createResponse(IsoMessage request)
	{
		Integer rtype = new Integer(request.getType() + 16);
		IsoMessage resp = new IsoMessage((String)isoHeaders.get(rtype));
		resp.setBinary(request.isBinary());
		resp.setType(request.getType() + 16);
		resp.setEtx(etx);
		IsoMessage templ = (IsoMessage)typeTemplates.get(rtype);
		if (templ != null)
		{
			for (int i = 2; i < 128; i++)
				if (templ.hasField(i))
					resp.setField(i, (IsoValue)templ.getField(i).clone());

		}
		for (int i = 2; i < 128; i++)
			if (request.hasField(i))
				resp.setField(i, (IsoValue)request.getField(i).clone());

		return resp;
	}

	public IsoMessage parseMessage(byte buf[], int begin, int isoHeaderLength)
		throws ParseException
	{
		IsoMessage m = new IsoMessage(ByteUtil.bytesToString(buf, begin, isoHeaderLength));
		int type = 0;
		type = buf[isoHeaderLength + begin] - 48 << 12 | buf[isoHeaderLength + begin + 1] - 48 << 8 | buf[isoHeaderLength + begin + 2] - 48 << 4 | buf[isoHeaderLength + begin + 3] - 48;
		m.setType(type);
		BitSet bs = new BitSet(64);
		int pos = 0;
		if (useBinary)
		{
			for (int i = isoHeaderLength + 2; i < isoHeaderLength + 10; i++)
			{
				int bit = 128;
				for (int b = 0; b < 8; b++)
				{
					bs.set(pos++, (buf[i] & bit) != 0);
					bit >>= 1;
				}

			}

			if (bs.get(0))
			{
				for (int i = isoHeaderLength + 10; i < isoHeaderLength + 18; i++)
				{
					int bit = 128;
					for (int b = 0; b < 8; b++)
					{
						bs.set(pos++, (buf[i] & bit) != 0);
						bit >>= 1;
					}

				}

				pos = 18 + isoHeaderLength;
			} else
			{
				pos = 10 + isoHeaderLength;
			}
		} else
		{
			for (int i = isoHeaderLength + begin + 4; i < isoHeaderLength + begin + 20; i++)
			{
				int hex = Integer.valueOf(buf[i] & 0xff).intValue();
				bs.set(pos++, (hex & 0x80) > 0);
				bs.set(pos++, (hex & 0x40) > 0);
				bs.set(pos++, (hex & 0x20) > 0);
				bs.set(pos++, (hex & 0x10) > 0);
				bs.set(pos++, (hex & 8) > 0);
				bs.set(pos++, (hex & 4) > 0);
				bs.set(pos++, (hex & 2) > 0);
				bs.set(pos++, (hex & 1) > 0);
			}

			pos = 20 + isoHeaderLength + begin;
		}
		Integer itype = new Integer(type);
		Map parseGuide = (Map)(Map)parseMap.get(itype);
		List index = (List)(List)parseOrder.get(itype);
		for (Iterator iter = index.iterator(); iter.hasNext();)
		{
			Integer i = (Integer)iter.next();
			FieldParseInfo fpi = (FieldParseInfo)parseGuide.get(i);
			if (bs.get(i.intValue() - 1))
			{
				IsoValue val = useBinary ? fpi.parseBinary(buf, pos) : fpi.parse(buf, pos);
				m.setField(i.intValue(), val);
				if (useBinary && val.getType() != IsoType.ALPHA && val.getType() != IsoType.LLVAR && val.getType() != IsoType.LLLVAR)
					pos += val.getLength() / 2 + val.getLength() % 2;
				else
					pos += val.getLength();
				if (val.getType() == IsoType.LLVAR)
					pos += useBinary ? 1 : 2;
				else
				if (val.getType() == IsoType.LLLVAR)
					pos += useBinary ? 2 : 3;
				else
				if (val.getType() == IsoType.LLLVARCN)
					pos += useBinary ? 2 : 3;
			}
		}

		return m;
	}

	public void setAssignDate(boolean flag)
	{
		setDate = true;
	}

	public boolean getAssignDate()
	{
		return setDate;
	}

	public void setTraceNumberGenerator(TraceNumberGenerator value)
	{
		traceGen = value;
	}

	public TraceNumberGenerator getTraceNumberGenerator()
	{
		return traceGen;
	}

	public void setIsoHeaders(Map value)
	{
		isoHeaders.clear();
		isoHeaders.putAll(value);
	}

	public void setIsoHeader(int type, String value)
	{
		if (value == null)
			isoHeaders.remove(new Integer(type));
		else
			isoHeaders.put(new Integer(type), value);
	}

	public String getIsoHeader(int type)
	{
		return (String)isoHeaders.get(new Integer(type));
	}

	public void addMessageTemplate(IsoMessage templ)
	{
		if (templ != null)
			typeTemplates.put(new Integer(templ.getType()), templ);
	}

	public void removeMessageTemplate(int type)
	{
		typeTemplates.remove(new Integer(type));
	}

	public void setParseMap(Integer type, Map map)
	{
		parseMap.put(type, map);
		ArrayList index = new ArrayList();
		index.addAll((Collection)map.keySet());
		Collections.sort(index);
		log.trace((new StringBuilder("Adding parse map for type ")).append(Integer.toHexString(type.intValue())).append(" with fields ").append(index).toString());
		parseOrder.put(type, index);
	}

}
